/**
 * 
 */
package ch.comtools.ssh.packet;

import java.nio.ByteBuffer;

/**
 * An SSH packet.
 * <pre>
 * uint32    packet_length
 * byte      padding_length
 * byte[n1]  payload; n1 = packet_length - padding_length - 1
 * byte[n2]  random padding; n2 = padding_length
 * byte[m]   mac (Message Authentication Code - MAC); m = mac_length
 * </pre>    
 * @author Roger Dudler <roger.dudler@gmail.com>
 * @version $Id$
 */
public class SSHPacket extends Packet {

	public SSHPacket() {
		super();
	}
	
	/**
	 * The length of the packet in bytes, not including 'mac' or the
	 * 'packet_length' field itself.<br>
	 * - <i>might be enrypted</i>
	 */
	public int length = 0;
	
	/**
	 * Length of 'random padding' (bytes)<br>
	 * - <i>might be enrypted</i>
	 */
	public byte paddingLength;
	
	/**
	 * The useful contents of the packet. If compression has been
	 * negotiated, this field is compressed. Initially, compression
	 * MUST be "none".<br>
	 * - <i>might be enrypted</i><br>
	 * - <i>might be compressed</i>
	 */
	public byte[] payload = new byte[] {};
	
	/**
	 * Arbitrary-length padding, such that total length of 
	 * (packet_length || padding_length || payload || random_padding)
	 * is a multiple of the cipher block or 8, whichever is
	 * larger. There MUST be at least four bytes of padding. The
	 * padding SHOULD consist of random bytes. The maximum amout
	 * of padding is 255.<br>
	 * - <i>might be enrypted</i>
	 */
	public byte[] randomPadding = new byte[] {};
	
	/**
	 * Message Authentication Code. If message authentication has
	 * been negotiated, this field contains the MAC bytes. Initially,
	 * the MAC algorithm MUST be "none".
	 */
	public byte[] mac = new byte[] {};
	
	/**
	 * @see ch.comtools.ssh.packet.Packet#getData()
	 */
	@Override
	public ByteBuffer getData() {
		this.paddingLength = (byte) (this.payload.length % 8);
		this.randomPadding = new byte[this.paddingLength];
		this.length = this.payload.length + this.randomPadding.length + 1;
		for (int i = 0; i < this.randomPadding.length; i++) {
			this.randomPadding[i] = (byte) 'A';
		}
		this.mac = new byte[] {};
		// TODO: set MAC
		this.buffer = ByteBuffer.allocate(this.length + this.mac.length + 4);
		buffer.putInt(this.length);
		buffer.put(this.paddingLength);
		buffer.put(this.payload);
		buffer.put(this.randomPadding);
		buffer.put(this.mac);
		return super.getData();
	}
	
	/**
	 * Prepare packet. Fill in header data.
	 * @param buffer
	 * @return payload
	 */
	public void read(ByteBuffer buffer) {
		this.length = buffer.getInt();
		this.paddingLength = buffer.get();
		int payloadLength = this.length - this.paddingLength - 1;
		this.payload = new byte[payloadLength];
		buffer.get(payload, 0, payloadLength);
		this.randomPadding = new byte[this.paddingLength];
		buffer.get(this.randomPadding, 0, this.paddingLength);
		this.mac = new byte[buffer.remaining()];
		buffer.get(this.mac);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Packet [" + 
			"Packet Length (Bytes): " + this.length + "; " + 
			"Padding Length (Bytes): " + this.paddingLength + "; " +
			"Payload (Bytes): " + this.payload.length + "; " +
			"Random Padding (Bytes): " + this.randomPadding.length + "; " +
			"Mac (Bytes): " + this.mac.length + "]";
	}
	
}
